#include "USART_Config.h"
#include "Delay.h"

// USB_to_TTL
USART_Config USART1_Cfg = {
    .USARTx = USART1,
    .GPIOx = GPIOA,
    .TX_Pin = GPIO_Pin_9,
    .RX_Pin = GPIO_Pin_10,
    .BaudRate = 115200,
    .name = "USART1",
};
// ESP-01s
USART_Config USART2_Cfg = {
    .USARTx = USART2,
    .GPIOx = GPIOA,
    .TX_Pin = GPIO_Pin_2,
    .RX_Pin = GPIO_Pin_3,
    .BaudRate = 115200,
    .name = "USART2",
};
// Blue_tooth
USART_Config USART3_Cfg = {
    .USARTx = USART3,
    .GPIOx = GPIOB,
    .TX_Pin = GPIO_Pin_10,
    .RX_Pin = GPIO_Pin_11,
    .BaudRate = 9600,
    .name = "USART3",
};


/**
 * @brief  配置USART引脚, 配置数据格式
 * @param  无
 * @retval 无
 */
void USART_Pin_Init(const USART_Config *cfg) {
	// 1.开启AFIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 
	
    // 2.开启 GPIOx 时钟
	if(cfg->GPIOx == GPIOA) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	if(cfg->GPIOx == GPIOB) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    // 3.配置输出引脚
    GPIO_InitTypeDef GPIO_InitStruct = {0};			// 定义结构体
    GPIO_InitStruct.GPIO_Pin = cfg->TX_Pin; 		// 结构体引脚
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;    // 结构体模式：【复用】推挽输出模式，需要单片机而非GPIOA模块进行操作
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  // 结构体速度：引脚输出速度可以选择2MHz,对于串口通信的慢速率来说（115200）,2MHz足矣
    GPIO_Init(cfg->GPIOx, &GPIO_InitStruct); 		// 初始化结构体

    // 4.配置输入引脚
    GPIO_InitStruct.GPIO_Pin = cfg->RX_Pin;  		  	 // 结构体引脚：9
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入模式：适合具有稳定输入的引脚，此处也可替换为上拉输入
    GPIO_Init(cfg->GPIOx, &GPIO_InitStruct);  			 // 初始化结构体
	
	// 5.给硬件时间稳定信号
	Delay_ms(1000);
	
	// 6.开启USATR时钟
	if(cfg->USARTx == USART1) RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	if(cfg->USARTx == USART2) RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	if(cfg->USARTx == USART3) RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
	
	// 7.利用USART_Init函数完成USART外设的初始化
    USART_InitTypeDef USART_InitStruct = {									// 定义结构体
		.USART_BaudRate = cfg->BaudRate,   									// 波特率设置为115200
		.USART_HardwareFlowControl = USART_HardwareFlowControl_None,    	// 不使用硬件流控
		.USART_Mode = USART_Mode_Rx | USART_Mode_Tx,    					// 设置为可收可发模式
		.USART_Parity = USART_Parity_No,    								// 不进行数据校验
		.USART_StopBits = USART_StopBits_1,     							// 选择1位停止位
		.USART_WordLength = USART_WordLength_8b,  	   						// 数据位是8位
	};
	USART_Init(cfg->USARTx, &USART_InitStruct);  						    // 初始化结构体

    // 8.使能开启USART1外设
    USART_Cmd(cfg->USARTx, ENABLE);					   						// 开启USART总开关
	
	// 9.清理接收数据寄存器
	USART_ClearRDR(cfg);  
}

// 读取PC发送的残留数据, 清空接收数据寄存器
void USART_ClearRDR(const USART_Config *cfg) {
    while (USART_GetFlagStatus(cfg->USARTx, USART_FLAG_RXNE) == SET) {
        USART_ReceiveData(cfg->USARTx); // 读接收数据寄存器但不存储，丢弃数据
    }
}

/**
 * @brief  通过USART1发送1个字节的数据
 * @param  待发送的1个字节数据
 * @retval 无
 */

void USART_SendByte(const USART_Config *cfg, uint8_t Byte){
    while(USART_GetFlagStatus(cfg->USARTx, USART_FLAG_TXE) == RESET); 	// 等发送缓冲区空
    USART_SendData(cfg->USARTx, Byte);
}


/**
 * @brief  通过USART发送字符串（以 '\0' 结尾）
 * @param  str指向字符串的指针
 * @retval 无
 */

void USART_SendString(const USART_Config *cfg, const char *str) {
    while (*str) {
        USART_SendByte(cfg, (uint8_t)*str++);
    }
    // 等待全部数据发送完毕
    while (USART_GetFlagStatus(cfg->USARTx, USART_FLAG_TC) == RESET);  
}


/*
 * @brief  通过USART发送格式化字符串（类似 printf）
 * @param  format  格式化字符串
 * @param  ...  可变参数
 * @retval 无
 */

void USART_printf(const USART_Config *cfg, const char *format, ...) {
    char buffer[1024];  			// 根据需求调整缓冲区大小
    va_list args;
    
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    USART_SendString(cfg, buffer);  // 调用已有的字符串发送函数
}


/**
 * @brief  通过USART发送格式化字符串（类似 printf）
 * @param  format  格式化字符串
 * @param  ...  可变参数
 * @retval 无
 */
 /*
void USART_printf(const char *format, ...) {
    char buffer[1024];  			// 根据需求调整缓冲区大小
    va_list args;
    
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    USART_SendString(&USART1_Cfg, buffer);  // 调用已有的字符串发送函数
}
*/

/**
 * @brief  通过USART1发送1个字节的数据到PC
 * @param  待发送的1个字节数据
 * @retval 无
 */
 /*
void USART_SendByte(uint8_t Byte){	
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); 	// 等发送缓冲区空
    USART_SendData(USART1, Byte);
}
*/

/**
 * @brief  通过 USART1 发送字符串（以 '\0' 结尾）到PC
 * @param  str  指向字符串的指针
 * @retval 无
 */
/*
void USART_SendString(const char *str) {
    while (*str) {
        USART_SendByte((uint8_t)*str++);
    }
    // 等待全部数据发送完毕
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);  
}
*/

/**
 * @brief  通过 USART1 发送格式化字符串（类似 printf）
 * @param  format  格式化字符串
 * @param  ...  可变参数
 * @retval 无
 */
/*
void USART_printf(const char *format, ...) {
    char buffer[MAX_STR_LEN];  // 根据需求调整缓冲区大小
    va_list args;
    
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    USART_SendString(buffer);  // 调用已有的字符串发送函数
}
*/

// 中断函数（版本1 | 会按照字符串发走，通过测试）
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE)) {
		static USART_Message msg = {.source_id = 1, .len = 0};
		BaseType_t stat = pdTRUE; 
        char ch = USART_ReceiveData(USART1);
		msg.data[msg.len++] = ch;
		
		if(ch == '\n' || ch == '\r') {  // 检测结束符
			msg.data[msg.len] = '\0';   // 添加终止符
			xQueueSendFromISR(xQueue, &msg, &stat);
			msg.len = 0;
		}

        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

void USART2_IRQHandler(void) {
    if (USART_GetITStatus(USART2, USART_IT_RXNE)) {
		static USART_Message msg = {.source_id = 2, .len = 0};
		BaseType_t stat = pdTRUE; 
        char ch = USART_ReceiveData(USART2);
		msg.data[msg.len++] = ch;
		
		if(ch == '\n' || ch == '\r') {  // 检测结束符
			msg.data[msg.len] = '\0';   // 添加终止符
			xQueueSendFromISR(xQueue, &msg, &stat);
			msg.len = 0;
		}

        USART_ClearITPendingBit(USART2, USART_IT_RXNE);
    }
}

void USART3_IRQHandler(void) {
    if (USART_GetITStatus(USART3, USART_IT_RXNE)) {
		static USART_Message msg = {.source_id = 3, .len = 0};
		BaseType_t stat = pdTRUE; 
        char ch = USART_ReceiveData(USART3);
		msg.data[msg.len++] = ch;
		
		if(ch == '\n' || ch == '\r') {  // 检测结束符
			msg.data[msg.len] = '\0';   // 添加终止符
			xQueueSendFromISR(xQueue, &msg, &stat);
			msg.len = 0;
		}

        USART_ClearITPendingBit(USART3, USART_IT_RXNE);
    }
}

/*
//// 在中断中发送到队列（版本2 | 会按照逐字符发走，需要后续处理）
//void USART1_IRQHandler(void) {
//    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
//    
//    if (USART_GetITStatus(USART1, USART_IT_RXNE)) {
//        uint8_t ch = USART_ReceiveData(USART1);
//        xQueueSendFromISR(xQueue, &ch, &xHigherPriorityTaskWoken);
//        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
//    }
//    
//    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
//}
*/

/**
 * @brief  配置USART外设的中断源, 以及初始化NVIC外设
 * @param  无
 * @retval 无
 * @note   
 */
void USART_NVIC_Init(const USART_Config *cfg){
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); 		 // 4位抢占优先级，无子优先级
	
	if(cfg->USARTx == USART1){
		// 在USART初始化代码中开启中断和空闲中断
		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  		 // 接收中断
		
		NVIC_EnableIRQ(USART1_IRQn);               				 // 使能USART全局中断
		
		NVIC_InitTypeDef NVIC_InitStruct = {
			.NVIC_IRQChannel = USART1_IRQn,
			.NVIC_IRQChannelPreemptionPriority = 12,  // 抢占优先级
			.NVIC_IRQChannelSubPriority = 0,          // 子优先级
			.NVIC_IRQChannelCmd = ENABLE,
		};
		NVIC_Init(&NVIC_InitStruct);
	}
	
	if(cfg->USARTx == USART2){
		// 在USART初始化代码中开启中断和空闲中断
		USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);  		 // 接收中断
		
		NVIC_EnableIRQ(USART2_IRQn);               				 // 使能USART全局中断
		
		NVIC_InitTypeDef NVIC_InitStruct = {
			.NVIC_IRQChannel = USART2_IRQn,
			.NVIC_IRQChannelPreemptionPriority = 12,  // 抢占优先级
			.NVIC_IRQChannelSubPriority = 0,          // 子优先级
			.NVIC_IRQChannelCmd = ENABLE,
		};
		NVIC_Init(&NVIC_InitStruct);
	}
	
	if(cfg->USARTx == USART3){
		// 在USART初始化代码中开启中断和空闲中断
		USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);  		 // 接收中断
		
		NVIC_EnableIRQ(USART3_IRQn);               				 // 使能USART全局中断
		
		NVIC_InitTypeDef NVIC_InitStruct = {
			.NVIC_IRQChannel = USART3_IRQn,
			.NVIC_IRQChannelPreemptionPriority = 12,  // 抢占优先级
			.NVIC_IRQChannelSubPriority = 0,          // 子优先级
			.NVIC_IRQChannelCmd = ENABLE,
		};
		NVIC_Init(&NVIC_InitStruct);
	}

}
